package br.edu.ifce.mflj.gui;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import javax.swing.ImageIcon;
import javax.swing.JPanel;

import br.edu.ifce.mflj.comunicacao.Pacote;
import br.edu.ifce.mflj.comunicacao.TipoPacote;
import br.edu.ifce.mflj.controller.IControlador;
import br.edu.ifce.mflj.dados.Casa;
import br.edu.ifce.mflj.dados.DimensoesTabuleiro;
import br.edu.ifce.mflj.dados.Peca;
import br.edu.ifce.mflj.dados.Usuario;
import br.edu.ifce.mflj.exception.PacoteInvalidoException;
import br.edu.ifce.mflj.regras.RegrasDamas;

public class TabuleiroPanel extends JPanel implements MouseMotionListener, MouseListener {
	private static final long	serialVersionUID	= -8416495964503345548L;

	private	Casa[][]			tabuleiro;
	private Graphics2D			graphic;
	private Integer				ultimoXMouse,
								ultimoYMouse;
	private Peca				pecaSelecionada;

	private Usuario				usuario;

	private IControlador		controlador;

	public TabuleiroPanel(){
		tabuleiro = new Casa[ 8 ][ 8 ];

		// Casas vazias do lado preto
		tabuleiro[ 0 ][ 0 ] = new Casa( 0, 0, null );
		tabuleiro[ 2 ][ 0 ] = new Casa( 2, 0, null );
		tabuleiro[ 4 ][ 0 ] = new Casa( 4, 0, null );
		tabuleiro[ 6 ][ 0 ] = new Casa( 6, 0, null );

		tabuleiro[ 1 ][ 1 ] = new Casa( 1, 1, null );
		tabuleiro[ 3 ][ 1 ] = new Casa( 3, 1, null );
		tabuleiro[ 5 ][ 1 ] = new Casa( 5, 1, null );
		tabuleiro[ 7 ][ 1 ] = new Casa( 7, 1, null );

		tabuleiro[ 0 ][ 2 ] = new Casa( 0, 2, null );
		tabuleiro[ 2 ][ 2 ] = new Casa( 2, 2, null );
		tabuleiro[ 4 ][ 2 ] = new Casa( 4, 2, null );
		tabuleiro[ 6 ][ 2 ] = new Casa( 6, 2, null );

		// Casas vazias do meio do tabuleiro
		for (int linha = 0; linha < tabuleiro.length; linha++) {
			for (int coluna = 0; coluna < tabuleiro[ linha ].length; coluna++ ){
				tabuleiro[ coluna ][ linha ] = new Casa( coluna, linha, null );
			}
		}

		// Casas vazias do lado branco
		tabuleiro[ 1 ][ 5 ] = new Casa( 1, 5, null );
		tabuleiro[ 3 ][ 5 ] = new Casa( 3, 5, null );
		tabuleiro[ 5 ][ 5 ] = new Casa( 5, 5, null );
		tabuleiro[ 7 ][ 5 ] = new Casa( 7, 5, null );

		tabuleiro[ 0 ][ 6 ] = new Casa( 0, 6, null );
		tabuleiro[ 2 ][ 6 ] = new Casa( 2, 6, null );
		tabuleiro[ 4 ][ 6 ] = new Casa( 4, 6, null );
		tabuleiro[ 6 ][ 6 ] = new Casa( 6, 6, null );

		tabuleiro[ 1 ][ 7 ] = new Casa( 1, 7, null );
		tabuleiro[ 3 ][ 7 ] = new Casa( 3, 7, null );
		tabuleiro[ 5 ][ 7 ] = new Casa( 5, 7, null );
		tabuleiro[ 7 ][ 7 ] = new Casa( 7, 7, null );
		
		// Peças pretas
		tabuleiro[ 1 ][ 0 ] = new Casa( 1, 0, Peca.PECA_PRETA );
		tabuleiro[ 3 ][ 0 ] = new Casa( 3, 0, Peca.PECA_PRETA );
		tabuleiro[ 5 ][ 0 ] = new Casa( 5, 0, Peca.PECA_PRETA );
		tabuleiro[ 7 ][ 0 ] = new Casa( 7, 0, Peca.PECA_PRETA );

		tabuleiro[ 0 ][ 1 ] = new Casa( 0, 1, Peca.PECA_PRETA );
		tabuleiro[ 2 ][ 1 ] = new Casa( 2, 1, Peca.PECA_PRETA );
		tabuleiro[ 4 ][ 1 ] = new Casa( 4, 1, Peca.PECA_PRETA );
		tabuleiro[ 6 ][ 1 ] = new Casa( 6, 1, Peca.PECA_PRETA );

		tabuleiro[ 1 ][ 2 ] = new Casa( 1, 2, Peca.PECA_PRETA );
		tabuleiro[ 3 ][ 2 ] = new Casa( 3, 2, Peca.PECA_PRETA );
		tabuleiro[ 5 ][ 2 ] = new Casa( 5, 2, Peca.PECA_PRETA );
		tabuleiro[ 7 ][ 2 ] = new Casa( 7, 2, Peca.PECA_PRETA );

		// Peças brancas
		tabuleiro[ 0 ][ 5 ] = new Casa( 0, 5, Peca.PECA_BRANCA );
		tabuleiro[ 2 ][ 5 ] = new Casa( 2, 5, Peca.PECA_BRANCA );
		tabuleiro[ 4 ][ 5 ] = new Casa( 4, 5, Peca.PECA_BRANCA );
		tabuleiro[ 6 ][ 5 ] = new Casa( 6, 5, Peca.PECA_BRANCA );

		tabuleiro[ 1 ][ 6 ] = new Casa( 1, 6, Peca.PECA_BRANCA );
		tabuleiro[ 3 ][ 6 ] = new Casa( 3, 6, Peca.PECA_BRANCA );
		tabuleiro[ 5 ][ 6 ] = new Casa( 5, 6, Peca.PECA_BRANCA );
		tabuleiro[ 7 ][ 6 ] = new Casa( 7, 6, Peca.PECA_BRANCA );

		tabuleiro[ 0 ][ 7 ] = new Casa( 0, 7, Peca.PECA_BRANCA );
		tabuleiro[ 2 ][ 7 ] = new Casa( 2, 7, Peca.PECA_BRANCA );
		tabuleiro[ 4 ][ 7 ] = new Casa( 4, 7, Peca.PECA_BRANCA );
		tabuleiro[ 6 ][ 7 ] = new Casa( 6, 7, Peca.PECA_BRANCA );

		addMouseMotionListener( this );
		addMouseListener( this );

	}

	/**
	 * @return the controlador
	 */
	public IControlador getControlador() {
		return controlador;
	}

	/**
	 * @param controlador the controlador to set
	 */
	public void setControlador(IControlador controlador) {
		this.controlador = controlador;
	}

	/**
	 * @return the usuario
	 */
	public Usuario getUsuario() {
		return usuario;
	}

	/**
	 * @param usuario the usuario to set
	 */
	public void setUsuario(Usuario usuario) {
		this.usuario = usuario;
	}

	@Override
	public void paintComponent( Graphics graphics ){
		super.paintComponent( graphics );
		this.graphic = (Graphics2D)graphics.create();

//		redesenharTabuleiro();
//		desenharPecas();

		this.graphic.dispose();
	}

	private void redesenharTabuleiro() {
		Image tabuleiro = new ImageIcon( "imagens/tabuleiro.png" ).getImage();
		graphic.drawImage( tabuleiro, 0, 0, 400, 400, this );
	}

	private void desenharPecas(){
		// Desenha todas as peças, menos a peça que estiver selecionada para movimento.
		for( int linha = 0; linha < 8; linha++ ){
			for( int coluna = 0; coluna < this.tabuleiro[ linha ].length; coluna++ ){
				try {
					if( tabuleiro[ coluna ][ linha ].isOcupada() ){
						Peca peca = tabuleiro[ coluna ][ linha ].getPeca();
						if( peca != pecaSelecionada ){
							graphic.drawImage(	peca.getImagem(),
												peca.getCoordenadaX(), 
												peca.getCoordenadaY(),
												DimensoesTabuleiro.LADO_CASA,
												DimensoesTabuleiro.LADO_CASA,
												this );
						}
					}
				} catch( NullPointerException nullPointerException ){}
			}
		}
		// Desenhar peça selecionada por último, para que fique por cima das demais.
		if( pecaSelecionada != null ){
			graphic.drawImage(	pecaSelecionada.getImagem(),
								pecaSelecionada.getCoordenadaX(), 
								pecaSelecionada.getCoordenadaY(),
								DimensoesTabuleiro.LADO_CASA,
								DimensoesTabuleiro.LADO_CASA,
								this );
		}
	}

	private int getLinha( int coordenadaX, int coordenadaY ){
		int valorYAbsoluto = coordenadaY - DimensoesTabuleiro.LIMITE_INICIAL_Y;

		if( !DimensoesTabuleiro.mouseDentroDoTabuleiro( coordenadaX, coordenadaY ) ){
			return DimensoesTabuleiro.FORA_DOS_LIMITES;
		}

		return ( valorYAbsoluto / DimensoesTabuleiro.LADO_CASA );
	}

	private int getColuna( int coordenadaX, int coordenadaY ){
		int valorXAbsoluto = coordenadaX - DimensoesTabuleiro.LIMITE_INICIAL_X;

		if( !DimensoesTabuleiro.mouseDentroDoTabuleiro( coordenadaX, coordenadaY ) ){
			return DimensoesTabuleiro.FORA_DOS_LIMITES;
		}

		return valorXAbsoluto / DimensoesTabuleiro.LADO_CASA;
	}

	@Override
	public void mousePressed( MouseEvent mouseEvent ){
		int	coluna	= getColuna( mouseEvent.getX(), mouseEvent.getY() ),
			linha	= getLinha( mouseEvent.getX(), mouseEvent.getY() );

		ultimoXMouse = mouseEvent.getX();
		ultimoYMouse = mouseEvent.getY();

		try {
			if(	( DimensoesTabuleiro.mouseDentroDoTabuleiro( mouseEvent.getX(), mouseEvent.getY() ) ) &&
				( tabuleiro[ coluna ][ linha ].isOcupada() ) ){
				if( tabuleiro[ coluna ][ linha ].getPeca().getTipoPeca().equals( Peca.PECA_PRETA ) ){
					pecaSelecionada = tabuleiro[ coluna ][ linha ].getPeca();

					try {
						controlador.transmitirPacote( new Pacote( TipoPacote.MOVIMENTO, mouseEvent, controlador.getIdentificadorCanalDeSaida(), controlador.getIdentificadorCanalDeSaida() ) );
						
					} catch (PacoteInvalidoException pacoteInvalidoException) {
						pacoteInvalidoException.printStackTrace();
					}
				}
			}
		} catch( NullPointerException nullPointerException ){}

	}

	@Override
	public void mouseDragged( MouseEvent mouseEvent ){
		if( pecaSelecionada != null && DimensoesTabuleiro.mouseDentroDoTabuleiro( mouseEvent.getX(), mouseEvent.getY() ) ){
			int		deslocamentoEmX = mouseEvent.getX() - ultimoXMouse,
					deslocamentoEmY	= mouseEvent.getY() - ultimoYMouse;

			pecaSelecionada.setCoordenadaX( pecaSelecionada.getCoordenadaX() + deslocamentoEmX );
			pecaSelecionada.setCoordenadaY( pecaSelecionada.getCoordenadaY() + deslocamentoEmY );

			ultimoXMouse = mouseEvent.getX();
			ultimoYMouse = mouseEvent.getY();

			super.repaint();
		}
	}

	@Override
	public void mouseReleased( MouseEvent mouseEvent ){
		int	casaX	= getColuna( mouseEvent.getX(), mouseEvent.getY() ),
			casaY	= getLinha( mouseEvent.getX(), mouseEvent.getY() );

		try {
			if( pecaSelecionada != null && RegrasDamas.movimentoPermitido( tabuleiro, tabuleiro[ casaX ][ casaY ], pecaSelecionada ) ){
				pecaSelecionada.setColuna( casaX );
				pecaSelecionada.setLinha( casaY );

			} else {
				pecaSelecionada.resetarPosicaoInicial();
			}

			try {
				controlador.transmitirPacote( new Pacote( TipoPacote.MOVIMENTO, mouseEvent, controlador.getIdentificadorCanalDeSaida(), controlador.getIdentificadorCanalDeSaida() ) );
				
			} catch (PacoteInvalidoException pacoteInvalidoException) {
				pacoteInvalidoException.printStackTrace();
			}
		}
		catch( NullPointerException nullPointerException ){}
		catch( ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException ){
			pecaSelecionada.resetarPosicaoInicial();
		}

		pecaSelecionada = null;


		super.repaint();
	}

	public void mouseMoved( MouseEvent mouseEvent ){}
	public void mouseClicked( MouseEvent mouseEvent ){}
	public void mouseEntered( MouseEvent mouseEvent ){}
	public void mouseExited( MouseEvent mouseEvent ){}

}
